package com.auction.job.core.schedule;

import com.auction.job.core.schedule.vo.JobInfo;
import com.yisu.auction.ewf.common.spring.SpringContext;
import org.quartz.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Random;

/**
 * Manage the task of quartz
 *
 */
public class QuartzManager {
	private static final Logger LOG = LoggerFactory.getLogger(QuartzManager.class);
	private static final String[] seconds = new String[] {"/5", "/6", "/4", "/7"};
	private static final String JOB_GROUP_NAME = "AUCTION_JOB_GROUP";
	private static final String TRIGGER_GROUP_NAME = "AUCTION_TRIGGER_GROUP";
//	private static final String PURCHASE_CRON_EXPRESSION = " * * * * ?";
	private static final String PURCHASE_CRON_EXPRESSION = " * * * * ?";
	private static final String OPEN_PRIZE_CRON_EXPRESSION = "/8 * * * * ?";
	private static final String DUPLICATION_JOB_CRON_EXPRESSION = "/15 * * * * ?";
	private static final String RESUME_JOB_CRON_EXPRESSION = "0 /1 * * * ?";
	private static final String ARCHIVE_PURCHASE_RECORD_CRON_EXPRESSION = "0 0/30 0-1,5-23 * * ?";
	private static final String PUSH_MESSAGE_CRON_EXPRESSION = "0 0/5 8-22 * * ?";
	private static final String COLLECT_REPORT_DATA_EXPRESSION = "0 0 4 * * ?";

	private static final String AUTO_PURCHASE_JOB_NAME_PREFIX = "purchase_";
	private static final String OPEN_JOB_NAME_PREFIX = "open_";
	private static final String DUPLICATION_JOB_NAME_PREFIX = "duplication_";
	private static final String RESUME_JOB = "resume_job";
	private static final String ARCHIVE_PURCHASE_RECORD_JOB = "archive_purchase_record_job";
	private static final String PUSH_MESSAGE_JOB_NAME = "push_message_job";
	private static final String COLLECT_REPORT_DATA_JOB_NAME = "report_data_job";

    private static Scheduler scheduler = (Scheduler) SpringContext.getBean("schedulerFactory");

	/**
	 *
	 */
	public static void startSystemJob() {
//		addArchiveJob();
//		ddResumeErrorJob();
	}

	/**
	 * Add a purchase job to scheduler
	 *
	 */
	public static boolean addPurchaseJob(String prizeId) {
		JobDataMap dataMap = new JobDataMap();
		dataMap.put("prizeId", prizeId);
		JobInfo jobInfo = new JobInfo();
		jobInfo.setDataMap(dataMap);
		jobInfo.setJobName(AUTO_PURCHASE_JOB_NAME_PREFIX + prizeId);
		jobInfo.setJobClass(AutoPurchaseJob.class);
		jobInfo.setCronExpression(getStartSecond() + PURCHASE_CRON_EXPRESSION);
		return addCronJob(jobInfo);
	}

	/**
	 * 添加推送JOB
	 * @return
	 */
	public static boolean addPushJob() {
		JobInfo jobInfo = new JobInfo();
		jobInfo.setJobName(PUSH_MESSAGE_JOB_NAME);
		jobInfo.setJobClass(PushJob.class);
		jobInfo.setCronExpression(PUSH_MESSAGE_CRON_EXPRESSION);
		return addCronJob(jobInfo);

	}

	private static String getStartSecond() {
		Random random = new Random();
		return seconds[random.nextInt(4)];
	}

	/**
	 * add a open prize job to schedule
	 *
	 * @return
	 */
	public static boolean addOpenPrizeJob(String prizeId) {
		try{
			removeOpenPrizeJob(prizeId);
		} catch (Exception e) {
			LOG.error("Failed to remove open job");
		}
		JobDataMap dataMap = new JobDataMap();
		dataMap.put("prizeId", prizeId);
		JobInfo jobInfo = new JobInfo();
		jobInfo.setDataMap(dataMap);
		jobInfo.setJobName(OPEN_JOB_NAME_PREFIX + prizeId);
		jobInfo.setJobClass(OpenPrizeJob.class);
		jobInfo.setCronExpression(OPEN_PRIZE_CRON_EXPRESSION);
		return addCronJob(jobInfo);
	}

	/**
	 *
	 * @param prizeId
	 * @param userId
	 * @return
	 */
	public static boolean addDupBuyJob(String prizeId, String userId) {
		JobDataMap dataMap = new JobDataMap();
		dataMap.put("prizeId", prizeId);
		dataMap.put("userId", userId);
		JobInfo jobInfo = new JobInfo();
		jobInfo.setDataMap(dataMap);
		jobInfo.setJobName(DUPLICATION_JOB_NAME_PREFIX + prizeId);
		jobInfo.setJobClass(DupBuyJob.class);
		jobInfo.setCronExpression(DUPLICATION_JOB_CRON_EXPRESSION);
		return addCronJob(jobInfo);
	}

	/**
	 *
	 * @return
	 */
	public static boolean addArchiveJob() {
		JobInfo jobInfo = new JobInfo();
		jobInfo.setJobName(ARCHIVE_PURCHASE_RECORD_JOB);
		jobInfo.setJobClass(ArchivePurchaseRecordJob.class);
		jobInfo.setCronExpression(ARCHIVE_PURCHASE_RECORD_CRON_EXPRESSION);
		return addCronJob(jobInfo);
	}


	/**
	 * Add a collect report data job to scheduler
	 *
	 */
	public static boolean addReportDataJob() {
		JobInfo jobInfo = new JobInfo();
		jobInfo.setJobName(COLLECT_REPORT_DATA_JOB_NAME);
		jobInfo.setJobClass(ReportDataJob.class);
		jobInfo.setCronExpression(COLLECT_REPORT_DATA_EXPRESSION);
		return addCronJob(jobInfo);
	}


	private static boolean addCronJob(JobInfo jobInfo) {
		String jobName = jobInfo.getJobName();
		JobDetail jobDetail = new JobDetail(jobName, JOB_GROUP_NAME, jobInfo.getJobClass());
		jobDetail.setJobDataMap(jobInfo.getDataMap());
		CronTrigger trigger = new CronTrigger(jobName, TRIGGER_GROUP_NAME);
		try {
			trigger.setCronExpression(jobInfo.getCronExpression());
			//trigger.setMisfireInstruction(CronTrigger.MISFIRE_INSTRUCTION_DO_NOTHING);
			scheduler.scheduleJob(jobDetail, trigger);
			LOG.info("Successfully added a job to scheduler, job name is [{}]", jobName);
			return true;
		} catch (Exception e) {
			LOG.error("Failed to add a job to scheduler, job name is [{}], cause: {}", jobName, e);
			return false;
		}
	}

	/**
	 * 添加一个以秒为执行间隔的JOB
	 *
	 * @param jobInfo
	 * @return
	 */
	private static boolean addIntervalInSecondsJob(JobInfo jobInfo) {
		String jobName = jobInfo.getJobName();
		JobDetail jobDetail = new JobDetail(jobName, JOB_GROUP_NAME, jobInfo.getJobClass());
		jobDetail.setJobDataMap(jobInfo.getDataMap());
		Trigger trigger = TriggerUtils.makeSecondlyTrigger(jobInfo.getIntervalInSeconds(), jobInfo.getRepeatCount());
		trigger.setName(jobName);
		try {
			scheduler.scheduleJob(jobDetail, trigger);
			LOG.info("Successfully added a job to scheduler, job name is [{}]", jobName);
			return true;
		} catch (Exception e) {
			LOG.error("Failed to add a job to scheduler, job name is [{}], cause: {}", jobName, e);
			return false;
		}
	}

	/**
	 * 删除购买JOB
	 *
	 * @param prizeId
	 */
	public static boolean removePurchaseJob(String prizeId) {
		String jobName = AUTO_PURCHASE_JOB_NAME_PREFIX + prizeId;
		return removeJob(jobName);
	}

	/**
	 * 删除开奖JOB
	 *
	 * @param prizeId
	 * @return
	 */
	public static boolean removeOpenPrizeJob(String prizeId) {
		String jobName = OPEN_JOB_NAME_PREFIX + prizeId;
		return removeJob(jobName);
	}


	/**
	 * 删除购买JOB
	 *
	 * @param prizeId
	 */
	public static boolean removeDupBuyJob(String prizeId) {
		String jobName = DUPLICATION_JOB_NAME_PREFIX + prizeId;
		return removeJob(jobName);
	}

	public static boolean removeArchiveJob() {
		String jobName = ARCHIVE_PURCHASE_RECORD_JOB;
		return removeJob(jobName);
	}

	public static boolean removeJob(String jobName) {
		try {
			scheduler.pauseTrigger(jobName, TRIGGER_GROUP_NAME);
			scheduler.unscheduleJob(jobName, TRIGGER_GROUP_NAME);
			scheduler.deleteJob(jobName, JOB_GROUP_NAME);
			LOG.info("Successfully removed a job for prize[{}].", jobName);
			return true;
		} catch (Exception e) {
			LOG.error("Failed to remove a job for prize[{}], root cause: {}", jobName, e);
			return false;
		}
	}

	/**
	 * 恢复出错的JOBS
	 */
	public static boolean addResumeErrorJob() {
		JobInfo jobInfo = new JobInfo();
		jobInfo.setJobName(RESUME_JOB);
		jobInfo.setJobClass(ResumeJob.class);
		jobInfo.setCronExpression(RESUME_JOB_CRON_EXPRESSION);
		return addCronJob(jobInfo);
	}

}
